package vectors;

import com.sun.deploy.util.ArrayUtil;

import java.util.Iterator;

public class LinkedListVector implements Vector {
	private static final long serialVersionUID = 1870362768235794718L;

    //TODO head - не верный смысл, так как даный елемент больше похож на tail
    private LinkedListVectorElement head;
	private int length;

    //TODO вызов метода super() не нужный
	public LinkedListVector() {
		super();
	}

	public LinkedListVector(double... values) {
		for (int i = 0; i < values.length; i++) {
			addElement(values[i]);
		}
	}

    //TODO данный метод достаточно большой и его можно раздробить
    //TODO общие методы должны быть public
//	void addElement(double value) {
//		length++;
//		LinkedListVectorElement cur = new LinkedListVectorElement(value);
//		if (head == null) {
//			head = cur;
//			head.setNext(head);
//			head.setPrevious(head);
//			return;
//		}
//		cur.setPrevious(head.getPrevious());
//		cur.setNext(head);
//		LinkedListVectorElement tmp = head.getPrevious();
//		tmp.setNext(cur);
//		head.setPrevious(cur);
//	}

    //TODO поправил
    public void addElement(double value) {
        LinkedListVectorElement cur = new LinkedListVectorElement(value);
        if (head == null)
            createHeadElement(cur);
        else
            createNextElement(cur);
    }

    //TODO общие методы должны быть public
	void deleteElement() {
		length--;
		if (head.getPrevious() == head) {
			head = null;
			return;
		}
		LinkedListVectorElement tmp = head.getPrevious().getPrevious();
		tmp.setNext(head);
		head.setPrevious(tmp);
	}

    //TODO плохо использовать break
    //TODO проверка index
	@Override
	public double getElement(int index) {
		LinkedListVectorElement cur = head;
        if(index >= 0 && index < length)
            for (int i = 0; i < index; i++)
                cur = cur.getNext();
        return cur.getValue();

//		for (int i = 0; i < length; i++) {
//			if (index == i) {
//				break;
//			}
//			cur = cur.getNext();
//		}
//		return cur.getValue();
	}

    //TODO тоже самое, что в getElement
	@Override
	public void setElement(int index, double value) {
		LinkedListVectorElement cur = head;
		for (int i = 0; i < length; i++) {
			if (index == i) {
				cur.setValue(value);
				break;
			}
			cur = cur.getNext();
		}
	}

	@Override
	public int getLength() {
		return length;
	}

	@Override
	public void fillFromAnArray(double[] source) {
		for (int i = 0; i < source.length; i++) {
			addElement(source[i]);
		}
	}

	@Override
	public void fillFromAnotherVector(Vector source) {
		for (int i = 0; i < source.getLength(); i++) {
			addElement(source.getElement(i));
		}
	}

	@Override
	public void multiplyByNumber(double number) {
		LinkedListVectorElement cur = head;
		do {
			double newValue = cur.getValue() * number;
			cur.setValue(newValue);
			cur = cur.getNext();
		} while (cur != head);
	}

	@Override
	public void add(Vector v) {
		if (length != v.getLength()) {
			System.out.println("Vectors can't be added.\n");
			return;
		}
		for (int i = 0; i < length; i++) {
			double newValue = getElement(i) + v.getElement(i);
			setElement(i, newValue);
		}
	}

	@Override
	public void compare(Vector v) {
		if (length != v.getLength()) {
			System.out.println("Vectors are different.\n");
			return;
		}
		for (int i = 0; i < length; i++) {
			if (getElement(i) != v.getElement(i)) {
				System.out.println("Vectors are different.\n");
				return;
			}
		}
		System.out.println("Vectors are equal.\n");
	}

	@Override
	public String toString() {
		StringBuffer s = new StringBuffer("LinkedListVector containing ");
		s.append(getLength());
		s.append(" elements which are:\n");
		for (int i = 0; i < getLength(); i++) {
			s.append(getElement(i));
			s.append('\n');
		}
		return s.toString();
	}

	@Override
	public boolean equals(Object obj) {
		if (!(obj instanceof Vector)) {
			return false;
		}
		Vector v = (Vector) obj;
		if (getLength() != v.getLength()) {
			return false;
		}
		for (int i = 0; i < getLength(); i++) {
			if (getElement(i) != v.getElement(i)) {
				return false;
			}
		}
		return true;
	}

	@Override
	public int hashCode() {
		int hashCode = 0;
		for (int i = 0; i < getLength(); i++) {
			Double element = getElement(i);
			hashCode ^= element.hashCode();
		}
		return hashCode;
	}

	@Override
	public Object clone() {
		LinkedListVector result = null;
		try {
			result = (LinkedListVector) super.clone();
		} catch (CloneNotSupportedException ex) {
		}
		result.head = null;
		result.length = 0;
		for (int i = 0; i < getLength(); i++) {
			result.addElement(getElement(i));
		}
		return result;
	}

	class LinkedListVectorIterator implements Iterator<Double> {
		private int index;

		public LinkedListVectorIterator() {
			index = 0;
		}

		@Override
		public boolean hasNext() {
			return index < length;
		}

		@Override
		public Double next() {
			return getElement(index++);
		}

		@Override
		public void remove() {

		}
	}

	@Override
	public Iterator<Double> iterator() {
		return new LinkedListVectorIterator();
	}

	public void printElements() {
		System.out.println("Vector has " + length + " elements.");
		if (length > 0) {
			LinkedListVectorElement cur = head;
			do {
				System.out.println(cur.getValue());
				cur = cur.getNext();
			} while (cur != head);
		}
		System.out.println();
	}

    private void createNextElement(LinkedListVectorElement cur)
    {
        cur.setPrevious(head.getPrevious());
        cur.setNext(head);
        LinkedListVectorElement tmp = head.getPrevious();
        tmp.setNext(cur);
        head.setPrevious(cur);
    }

    private void createHeadElement(LinkedListVectorElement cur)
    {
        head = cur;
        head.setNext(head);
        head.setPrevious(head);
    }
}
